package cn.com.cym.gamezao.service.authorize.impl;

import cn.com.cym.gamezao.base.BaseImpl;
import cn.com.cym.gamezao.base.BaseRepository;
import cn.com.cym.gamezao.base.ResultResponse;
import cn.com.cym.gamezao.base.SearchPage;
import cn.com.cym.gamezao.entity.authorize.Authorize;
import cn.com.cym.gamezao.entity.authorize.Role;
import cn.com.cym.gamezao.entity.authorize.User;
import cn.com.cym.gamezao.exception.BaseException;
import cn.com.cym.gamezao.repository.authorize.AuthorizeRepository;
import cn.com.cym.gamezao.service.authorize.AuthorizeService;
import cn.com.cym.gamezao.util.CommonUtils;
import cn.hutool.core.util.ReflectUtil;
import lombok.SneakyThrows;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;


@Service
@Transactional(rollbackFor = Exception.class)
public class AuthorizeImpl extends BaseImpl<Authorize> implements AuthorizeService {

    final AuthorizeRepository thisRepository;

    public AuthorizeImpl(AuthorizeRepository authorizeRepository){
        this.thisRepository=authorizeRepository;
    }

    @Override
    public BaseRepository<Authorize, Long> getJpaRepository() {
        return this.thisRepository;
    }

    @Override
    public Page<Authorize> findByPageable(SearchPage searchPage) {
        String[] sortBy = searchPage.getSortBy().toArray(new String[searchPage.getSortBy().size()]);

        Pageable pageable = PageRequest.of(searchPage.getCurrent()-1, searchPage.getPageSize(), searchPage.getSort(), sortBy);

        Specification<Authorize> specification = new Specification<>() {

            private static final long serialVersionUID = -2661077778894635593L;

            /**
             * @param root: 代表查询的实体类.
             * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
             * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.
             * @param  cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
             * @return  Predicate 类型, 代表一个查询条件.
             */
            @SneakyThrows
            @Override
            public Predicate toPredicate(Root<Authorize> root,
                                         CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Map<String, Field> fieldMap = ReflectUtil.getFieldMap(Authorize.class);
                return cb.and(CommonUtils.pageSet(fieldMap,searchPage,cb,root));
            }
        };
        return this.thisRepository.findAll(specification, pageable);
    }


    /**
     * 根据code获取权限
     * @param code code
     * @return role
     */
    private Authorize getByCode(String code){
        return this.thisRepository.getByCode(code);
    }

    @Override
    public Authorize save(Authorize authorize) {
        final Authorize byCode = this.getByCode(authorize.getCode());
        if(authorize.getId()==null){
            if(byCode!=null && byCode.getId()!=null){
                throw new BaseException("已经存在相同的权限编码,不能新建",new ResultResponse("已经存在相同的权限编码,不能新建", HttpStatus.BAD_REQUEST.value()));
            }
        }else{
            if(byCode!=null && byCode.getId()!=null && !authorize.getId().equals(byCode.getId())){
                throw new BaseException("已经存在相同的权限编码，不可修改成该编码",new ResultResponse("已经存在相同的权限编码，不可修改成该编码", HttpStatus.BAD_REQUEST.value()));
            }
        }
        final Authorize save = super.save(authorize);
        //save.setAuthorizes(authorize.getAuthorizes());
        //save.getAuthorizes().addAll((authorize.getAuthorizes()));
        //如果有父类和子类全是重建的，需要对对象父类保存
        if(authorize.getSysMenu() && authorize.getAuthorizes().size()>0){
            for(Authorize authorize1:save.getAuthorizes()){
                authorize1.setAuthorize(save);
                this.save(authorize1);
            }
        }
        return save;
    }

    @Override
    public List<Authorize> getAllMenu() {
        return this.thisRepository.getBySysMenu(true);
    }
}
